__author__ = 'Muscle'
from mui.muicomponent import *
from mui import color
import mui.CExt.muiDX as muiDX

class TextBase(object):
    _fontWeightMap = {'THIN': muiDX.DWRITE_FONT_WEIGHT_THIN, 'EXTRA_LIGHT': muiDX.DWRITE_FONT_WEIGHT_EXTRA_LIGHT, 'REGULAR': muiDX.DWRITE_FONT_WEIGHT_REGULAR,
                      'LIGHT': muiDX.DWRITE_FONT_WEIGHT_LIGHT, 'NORMAL': muiDX.DWRITE_FONT_WEIGHT_NORMAL, 'MEDIUM': muiDX.DWRITE_FONT_WEIGHT_MEDIUM,
                    'DEMI_BOLD':muiDX.DWRITE_FONT_WEIGHT_DEMI_BOLD, 'SEMI_BOLD': muiDX.DWRITE_FONT_WEIGHT_SEMI_BOLD, 'BOLD':muiDX.DWRITE_FONT_WEIGHT_BOLD,
                     'EXTRA_BOLD':muiDX.DWRITE_FONT_WEIGHT_EXTRA_BOLD, 'ULTRA_BOLD':muiDX.DWRITE_FONT_WEIGHT_ULTRA_BOLD, 'BLACK':muiDX.DWRITE_FONT_WEIGHT_BLACK,
                      'HEAVY':muiDX.DWRITE_FONT_WEIGHT_HEAVY, 'EXTRA_BLACK':muiDX.DWRITE_FONT_WEIGHT_EXTRA_BLACK }
    _fontStyleMap = {'NORMAL': muiDX.DWRITE_FONT_STYLE_NORMAL, 'OBLIQE': muiDX.DWRITE_FONT_STYLE_OBLIQUE, 'ITALIC': muiDX.DWRITE_FONT_STYLE_ITALIC}
    _fontStretchMap = {'ULTRA_CONDENSED': muiDX.DWRITE_FONT_STRETCH_ULTRA_CONDENSED, 'EXTRA_CONDENSED': muiDX.DWRITE_FONT_STRETCH_EXTRA_CONDENSED,
                        'CONDENSED': muiDX.DWRITE_FONT_STRETCH_CONDENSED, 'SEMI_CONDENSED': muiDX.DWRITE_FONT_STRETCH_SEMI_CONDENSED , 'NORMAL': muiDX.DWRITE_FONT_STRETCH_NORMAL,
                        'MEDIUM': muiDX.DWRITE_FONT_STRETCH_MEDIUM , 'SEMI_EXPANDED': muiDX.DWRITE_FONT_STRETCH_SEMI_EXPANDED,
                        'EXPANDED': muiDX.DWRITE_FONT_STRETCH_EXPANDED, 'EXTRA_EXPANDED': muiDX.DWRITE_FONT_STRETCH_EXTRA_EXPANDED,
                        'ULTRA_EXPANDED': muiDX.DWRITE_FONT_STRETCH_ULTRA_EXPANDED}
    _textAlignMap = {'LEFT': muiDX.DWRITE_TEXT_ALIGNMENT_LEADING,  'CENTER': muiDX.DWRITE_TEXT_ALIGNMENT_CENTER, 'RIGHT': muiDX.DWRITE_TEXT_ALIGNMENT_TRAILING}
    _paraAlignMap = {'TOP': muiDX.DWRITE_PARAGRAPH_ALIGNMENT_NEAR, 'CENTER': muiDX.DWRITE_PARAGRAPH_ALIGNMENT_CENTER,'BOTTOM': muiDX.DWRITE_PARAGRAPH_ALIGNMENT_FAR}
    _formatProp = ('fontSize', 'fontFamilyName', 'fontWeight', 'fontStyle', 'fontStrength', 'localeName')
    _alignProp = ('textAlign', 'paraAlign')

    def __init__(self, **kwargs):
        self.text = ''
        self.textMargin = [0, 0]
        self.fontColor = (1.0, 1.0, 1.0, 1.0)
        self.fontSize = 14
        self.fontFamilyName = kwargs.get('fontFamilyName', 'RockWell')
        self.fontWeight = kwargs.get('fontWeight', 'Regular')
        self.fontStyle = kwargs.get('fontStyle', 'Normal')
        self.fontStretch = kwargs.get('fontStretch', 'Normal')
        self.localeName = kwargs.get('localeName','en-us')
        self.textAlign = kwargs.get('textAlign', 'center')
        self.paraAlign = kwargs.get('paraAlign', 'center')
        self.bMultiLine = True
        self._textLayout = None
        self._textMetrics = None
        

        self.setDefault(**kwargs)
        self.changeEvent('fontSize', self.updateTextLayout, actArgs = ("fontSize",))
        self.changeEvent('fontFamilyName', self.updateTextLayout, actArgs = ("fontFamilyName",))
        self.changeEvent('fontWeight', self.updateTextLayout,  actArgs = ("fontWeight",))
        self.changeEvent('fontStyle', self.updateTextLayout, actArgs =  ("fontStyle",))
        self.changeEvent('fontStretch', self.updateTextLayout, actArgs = ("fontStretch",))
        self.changeEvent('localName', self.updateTextLayout,  actArgs = ("localName",))
        self.changeEvent('textAlign', self.updateTextLayout,  actArgs = ("textAlign",))
        self.changeEvent('paraAlign', self.updateTextLayout,  actArgs = ("paraAlign",))
        self.changeEvent('bMultiLine', self.updateTextLayout,  actArgs = ("bMultiLine",))
        self.changeEvent('text', self.updateTextLayout,  actArgs = ('text',))
        self.changeEvent('textMargin', self.updateTextLayout,  actArgs = ('textMargin',))
        self.bind('Size Change', self.updateTextLayout, 'Size Change', noarg = True, postEvent = True)

    def _createTextLayout(self):
        try:
            dxDevice = self.window.dxDevice
            if (self._textLayout != None):
                self._textLayout.Release()
                self._textLayout = None
                self._textMetrics = None
            text = self.getContent()
            fontSize = self.fontSize
            fontFamilyName = self.fontFamilyName
            fontWeight = self._fontWeightMap[self.fontWeight.upper()]
            fontStyle = self._fontStyleMap[self.fontStyle.upper()]
            fontStretch = self._fontStretchMap[self.fontStretch.upper()]
            localeName = self.localeName
            maxWidth = self.width - self.textMargin[0]*2
            maxHeight = self.height - self.textMargin[1]*2
            if (not self.bMultiLine):
                text = self.truncateText(text, maxWidth)
            hr, textFormat = dxDevice.CreateTextFormat(fontSize, unicode(fontFamilyName), None, fontWeight, fontStyle, fontStretch, unicode(localeName) )
            self._textLayout = dxDevice.CreateTextLayoutEx(unicode(text), maxWidth, maxHeight, textFormat )
            textFormat.Release()

            textAlign = self._textAlignMap[self.textAlign.upper()]
            self._textLayout.SetTextAlignment(textAlign)
            paraAlign = self._paraAlignMap[self.paraAlign.upper()]
            self._textLayout.SetParagraphAlignment(paraAlign)
            
            if (self._textMetrics == None):
                self._textMetrics = muiDX.DWRITE_TEXT_METRICS()
            self._textLayout.GetMetrics(self._textMetrics)
        except Exception, e:
            traceback.print_exc()
            return None

    def updateTextLayout(self, attr):
        try:
            from mui.Widgets.muitooltips import MUITooltips
            dxDevice = self.window.dxDevice
            if (self._textLayout == None):
                self._createTextLayout()
            else:
                textRange = muiDX.DWRITE_TEXT_RANGE()
                textRange.startPosition = 0
                textRange.length = len(self.text)
                if (attr == 'Size Change'):
                    hr = self._textLayout.SetMaxWidth(self.width)
                    hr = self._textLayout.SetMaxHeight(self.height)
                elif (attr == 'text'):
                    self._createTextLayout()
                elif (attr == 'fontSize'):
                    self._textLayout.SetFontSize(self.fontSize, textRange)
                elif (attr == 'fontFamilyName'):
                    self._textLayout.SetFontFamilyName(unicode(self.fontFamilyName), textRange)
                elif (attr == 'fontWeight'):
                    fontWeight = self._fontWeightMap[self.fontWeight.upper()]
                    self._textLayout.SetFontWeight(fontWeight, textRange)
                elif (attr == 'fontStretch'):
                    fontStretch = self._fontStretchMap[self.fontStretch.upper()]
                    self._textLayout.SetFontStretch(fontStretch, textRange)
                elif ( attr == 'localeName'):
                    self._textLayout.SetLocaleName(unicode(self.localeName), textRange)
                elif (attr == 'textAlign'):
                    textAlign = self._textAlignMap[self.textAlign.upper()]
                    self._textLayout.SetTextAlignment(textAlign)
                elif (attr == 'paraAlign'):
                    paraAlign = self._paraAlignMap[self.paraAlign.upper()]
                    self._textLayout.SetParagraphAlignment(paraAlign)
                elif (attr == 'bMultiLine'):
                    self._createTextLayout()

            if (self._textMetrics == None):
                self._textMetrics = muiDX.DWRITE_TEXT_METRICS()
            self._textLayout.GetMetrics(self._textMetrics)
            self.setDirty(True)
            if (isinstance(self, MUIEventDispatcher)):
                self.dispatch_event('TextLayout Update')
        except Exception, e:
            traceback.print_exc()
            return None

    def __getTextSize(self):
        if (self._textMetrics == None):
             if (self._textLayout == None):
                 self.updateTextLayout('text')
             self._textLayout.GetMetrics(self._textMetrics)
        return self._textMetrics.width, self._textMetrics.height

    textSize = property(__getTextSize)

    def __getTextPos(self):
        if (self._textMetrics == None):
            return (0, 0)
        return self._textMetrics.left, self._textMetrics.top
    textPosition = property(__getTextPos)

    def draw(self, renderer, pos = None):
        if not pos:
            pos = self.textMargin
        if (self._textLayout != None):
            renderer.DrawColorTextLayout((pos[0], pos[1]), self._textLayout, self.fontColor)

    def calTextSize(self, text, **kwargs):
        dxDevice = self.window.dxDevice
        fontSize = 14
        fontFamilyName = kwargs.get('fontFamilyName', self.fontFamilyName)
        fontWeight = kwargs.get('fontWeight', self.fontWeight)
        fontStyle = kwargs.get('fontStyle', self.fontStyle)
        fontStretch = kwargs.get('fontStretch', self.fontStretch)
        localeName = kwargs.get('localeName', self.localeName)
        textAlign = kwargs.get('textAlign', self.textAlign)
        paraAlign = kwargs.get('paraAlign', self.paraAlign)
        maxWidth =  kwargs.get('maxWidth', self.width)
        maxHeight = kwargs.get('maxHeight', self.height)
        # create TextLayout
        fontStyle = self._fontStyleMap[fontStyle.upper()]
        fontStretch = self._fontStretchMap[fontStretch.upper()]
        fontWeight = self._fontWeightMap[fontWeight.upper()]
        hr, textFormat = dxDevice.CreateTextFormat(fontSize, unicode(fontFamilyName), None, fontWeight, fontStyle, fontStretch, unicode(localeName) )
        _textLayout = dxDevice.CreateTextLayoutEx(unicode(text), maxWidth, maxHeight, textFormat )
        textFormat.Release()

        textAlign = self._textAlignMap[textAlign.upper()]
        _textLayout.SetTextAlignment(textAlign)
        paraAlign = self._paraAlignMap[paraAlign.upper()]
        _textLayout.SetParagraphAlignment(paraAlign)


        _textMetrics = muiDX.DWRITE_TEXT_METRICS()
        _textLayout.GetMetrics(_textMetrics)
        tw, th = _textMetrics.width, _textMetrics.height
        return tw, th

    def truncateText(self, text, maxWidth, postString = '...'):
        content = text
        constraint = self.width
        truncated = ''
        remain = content
        w = 0
        if (postString):
            w = self.calTextSize(postString)[0]
        if w > constraint:
            return postString

        while remain:
            h = (len(remain) + 1) / 2
            concat, remain = remain[:h], remain[h:]
            display = truncated + concat + postString
            w = self.calTextSize(display, maxWidth = 10000)[0]
            if w == constraint:     # luckily equal to constraint
                return display
            elif w < constraint:    # less than constraint
                truncated += concat
            elif len(concat) > 1:   # over constraint
                remain = concat
            else:                   # over constraint even only one more character
                remain = None
        return truncated + postString


    def getContent(self):
        return self.text

class MUIText(MUIComponent, TextBase):
    def __init__(self, parent=None, **kwargv):
        MUIComponent.__init__(self, parent, **kwargv)
        TextBase.__init__(self, **kwargv)
       # property
        self.autosize = kwargv.get('autosize', False)
        self.bind('TextLayout Update', self.onAutoSize)

    def on_draw(self, renderer):
        super(MUIText, self).on_draw(renderer)
        TextBase.draw(self, renderer)

    def onAutoSize(self):
        if self.autosize:
            self.size = self.textSize